package com.yizisu.basemvvm.mvvm


import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.graphics.Point
import android.graphics.Rect
import android.os.Bundle
import android.view.*
import android.view.animation.AnimationUtils
import android.widget.FrameLayout
import androidx.annotation.StyleRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.*
import com.yizisu.basemvvm.R
import com.yizisu.basemvvm.mvvm.mvvm_helper.*
import com.yizisu.basemvvm.utils.*

/**
 * 若红楼梦空，亦初心不变
 * 作者：thinker
 * 包名：com.yizisu.basemvvm.mvvm
 * 时间：2019/1/26 10:18
 * 描述：
 */
abstract class MvvmDialog : AppCompatDialogFragment(), BaseMvvmInterface {
    //外面传入的对象
    private var outLife: LifecycleOwner? = null
    private val safeDismissData by lazy {
        val data = MutableLiveData<Any?>()
        data.observe(this, Observer {
            dismiss()
        })
        data
    }
    private val safeShowData by lazy {
        val data = MutableLiveData<FragmentManager?>()
        outLife?.let {
            data.observe(it, Observer { fgm ->
                if (fgm != null) {
                    tryError {
                        show(fgm, javaClass.simpleName)
                    }
                }
            })
        }
        data
    }
    private val contentViewLp = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
    )

    val appCompatActivity: AppCompatActivity?
        get() = activity as? AppCompatActivity

    /**
     * 动态权限请求码，随意
     */
    private val needPermissionCode = 1450
    /**
     * 动态权限的回调，是否有此权限
     */
    private var needPermissionCall: Function1<Boolean, Unit>? = null

    /**
     * viewModel
     */
    inline fun <reified M : MvvmViewModel> getActivityViewModel(): M? {
        return if (activity == null) null else ViewModelProvider(activity!!).get(M::class.java)
    }

    /**
     * 获取依赖的fragment的viewModel
     */
    inline fun <reified M : MvvmViewModel> getParentFragmentViewModel(): M? {
        val life = parentFragment
        return if (life == null) null else ViewModelProvider(life).get(M::class.java)
    }

    /**
     * 创建其他格式的viewModel
     */
    inline fun <reified P : MvvmViewModel> getViewModel(): P {
        return ViewModelProvider(this).get(P::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initViewModel()
    }

    /**
     * 如果atLocationBean不是null，就代表本次弹窗类似于popupWindow
     */
    private data class AtLocationBean(val anchor: View, val isGravityEnd: Boolean, val xoff: Int = 0, val yoff: Int = 0)

    private var atLocationBean: AtLocationBean? = null

    /**
     * 创建view
     */
    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        val contentView = getLayoutResOrView(inflater)
        val rootView = FrameLayout(inflater.context)
        onRootViewLayoutParams(contentViewLp)
        val contentViewGroup = when (contentView) {
            is Int -> {
                inflater.inflate(contentView, container, false)
            }
            is View -> {
                contentView
            }
            else -> {
                null
            }
        }
        contentViewGroup?.let {
            rootView.addView(contentViewGroup, contentViewLp)
            rootView.setOnClickListener {
                if (isCanceledOnTouchOutside()) {
                    safeDismiss()
                }
            }
            contentViewGroup.setOnClickListener(null)
        }
        setDialogWindowAnim()
        return rootView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initUi(savedInstanceState)
        getClickView()?.forEach {
            it?.setOnClickListener(this)
        }
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        initData()
        MessageBus.register(this)
    }

    override fun onDestroyView() {
        MessageBus.unRegister(this)
        super.onDestroyView()
    }

    override fun onDestroy() {
        outLife = null
        super.onDestroy()
    }

    /**
     * 开始进入动画
     */
    private fun setDialogWindowAnim() {
        val locationBean = atLocationBean
        //如果是通过调用showAsDropTopOrBottom显示的对话框，取消动画
        //因为这里的动画是整个对话框，但是整个对话框是全屏的，
        // 这里我们可能只需要自己布局的动画，如果有需要自行处理
        getShowViewLocation(locationBean)
        if (locationBean != null) {
            return
        }
        if (!isNeedDefaultAnim()) {
            return
        }
        val anim = getDialogAnim()
        if (anim != null) {
            dialog?.window?.setWindowAnimations(anim)
        } else {
            dialog?.window?.setWindowAnimations(
                    when (contentViewLp.gravity) {
                        Gravity.BOTTOM -> {
                            R.style.PopupWindowBottomIn
                        }
                        Gravity.TOP -> {
                            R.style.PopupWindowTopIn
                        }
                        else -> {
                            R.style.AnimScaleCenter
                        }
                    }
            )
        }
    }


    /**
     * 设置view显示位置
     */
    private fun getShowViewLocation(locationBean: AtLocationBean?) {
        locationBean ?: return
        val anchor = locationBean.anchor
        val xoff = locationBean.xoff
        val yoff = locationBean.yoff
        val lp = contentViewLp
        val touch = intArrayOf(0, 0)
        val screenPoint = Point()
        locationBean.anchor.display.getRealSize(screenPoint)
        locationBean.anchor.getLocationOnScreen(touch)
        val isShowBottom = touch[1] < screenPoint.y / 2
        return if (isShowBottom) {
            //如果有状态栏，需要减去状态栏高度
            //经过未完全测试，不论怎样都有状态栏高度
            val topMargin = touch[1] + anchor.height + yoff - resources.getStatusBarHeight()
            if (locationBean.isGravityEnd) {
                lp.gravity = Gravity.TOP or Gravity.END
                lp.topMargin = topMargin
                lp.marginEnd = screenPoint.x - touch[0] - anchor.width + xoff

            } else {
                lp.gravity = Gravity.TOP or Gravity.START
                lp.topMargin = topMargin
                lp.marginStart = touch[0] + xoff
            }
        } else {
            //如果有导航栏，需要减去导航栏高度，这里投方便暂时没做判断
//            val bottomMargin = screenPoint.y - touch[1] + yoff - resources.getNavigationBarHeight()
            val bottomMargin = screenPoint.y - touch[1] + yoff
            if (locationBean.isGravityEnd) {
                lp.gravity = Gravity.BOTTOM or Gravity.END
                lp.bottomMargin = bottomMargin
                lp.marginEnd = screenPoint.x - touch[0] - anchor.width + xoff
            } else {
                lp.gravity = Gravity.BOTTOM or Gravity.START
                lp.bottomMargin = bottomMargin
                lp.marginStart = touch[0] + xoff
            }
        }
    }

    /**
     * 当生命周期可见的时候再取消对话框
     */
    fun safeDismiss() {
        safeDismissData.value = "dismiss dialog"
        safeShowData.value = null
    }

    override fun dismiss() {
        if (dialog?.isShowing != true) {
            return
        }
        safeShowData.value = null
        try {
            super.dismiss()
        } catch (e: Exception) {
            dismissAllowingStateLoss()
        }
    }

    /**
     * 请求用户权限
     */
    override fun getPermission(
            permission: MutableList<String>,
            needPermissionCall: Function1<Boolean, Unit>
    ) {
        if (context == null) {
            return
        }
        var isNeedRequest = false
        val list = mutableListOf<String>()
        permission.forEach {
            if (ActivityCompat.checkSelfPermission(
                            context!!,
                            it
                    ) != PackageManager.PERMISSION_GRANTED
            ) {
                isNeedRequest = true
                list.add(it)
            }
        }
        if (isNeedRequest) {
            this.needPermissionCall = needPermissionCall
            if (list.isNotEmpty()) {
                requestPermissions(list.toTypedArray(), needPermissionCode)
            } else {
                needPermissionCall.invoke(true)
            }
        } else {
            needPermissionCall.invoke(true)
        }
    }

    /**
     * 处理请求的权限结果
     */
    override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == needPermissionCode) {
            var isGetAllPermission = true
            grantResults.forEach {
                if (it != PackageManager.PERMISSION_GRANTED) {
                    isGetAllPermission = false
                }
            }
            needPermissionCall?.invoke(isGetAllPermission)
        }
    }


    /**
     * 注册livedata，忽略空的情况
     */
    inline fun <T> LiveBean<T>.register(crossinline observer: (LiveBean<T>) -> Unit): Observer<LiveBeanValue<T>> {
        return registerLiveBean(this@MvvmDialog, observer)
    }

    /**
     * 注册livedata，只处理成功的情况
     */
    inline fun <T> LiveBean<T>.registerOnSuccess(crossinline success: (T) -> Unit): Observer<LiveBeanValue<T>> {
        return registerOnSuccessLiveBean(this@MvvmDialog, success)
    }

    /**
     * 注册livedata，忽略空的情况
     */
    inline fun <T> MediatorLiveBean<T>.register(crossinline observer: (MediatorLiveBean<T>) -> Unit): Observer<LiveBeanValue<T>> {
        return registerLiveBean(this@MvvmDialog, observer)
    }

    /**
     * 注册livedata，只处理成功的情况
     */
    inline fun <T> MediatorLiveBean<T>.registerOnSuccess(crossinline success: (T) -> Unit): Observer<LiveBeanValue<T>> {
        return registerOnSuccessLiveBean(this@MvvmDialog, success)
    }

    /************************对于dialog下面是额外的功能***************************/
    override fun onStart() {
        super.onStart()
        dialog?.setCanceledOnTouchOutside(isCanceledOnTouchOutside())
        dialog?.window?.apply {
            attributes?.let {
                it.width = WindowManager.LayoutParams.MATCH_PARENT
                val outRect = Rect()
                appCompatActivity?.window?.decorView?.getWindowVisibleDisplayFrame(outRect)
                val height = outRect.height()
                it.height = if (height > 0) height else WindowManager.LayoutParams.MATCH_PARENT
                it.dimAmount = getDialogDimAmount()
                dialog?.window?.attributes = it
            }
            setBackgroundDrawableResource(android.R.color.transparent)
        }
    }


    fun show(activity: FragmentActivity?) {
        activity?.let {
            tryError {
                show(it.supportFragmentManager, javaClass.simpleName)
            }
        }
    }

    fun show(fragment: Fragment?) {
        fragment?.parentFragmentManager?.let {
            tryError {
                show(it, javaClass.simpleName)
            }
        }
    }

    /**
     * 显示在按钮的上方或者下方
     *  isGravityEnd : true ,弹窗与view的右边缘对齐，可以通过设置xoff来横向偏移
     *  isGravityEnd : false ,弹窗与view的左边缘对齐，可以通过设置xoff来横向偏移
     */
    fun showAsDropTopOrBottom(anchor: View, isGravityEnd: Boolean, xoff: Int = 0, yoff: Int = 0) {
        atLocationBean = AtLocationBean(anchor, isGravityEnd, xoff, yoff)
        when (val ctx = anchor.context) {
            is AppCompatActivity -> {
                show(ctx)
            }
            is ContextWrapper -> {
                show(ctx.baseContext.safeGet<AppCompatActivity>())
            }
        }
    }

    /**
     * 当生命周期可见再显示对话框
     */
    fun safeShow(fragmentActivity: FragmentActivity?) {
        val fgm = fragmentActivity?.supportFragmentManager ?: return
        outLife = fragmentActivity
        safeShowData.value = fgm
    }

    /**
     * 当生命周期可见再显示对话框
     */
    fun safeShow(fragment: Fragment?) {
        val fgm = fragment?.fragmentManager ?: return
        outLife = fragment
        safeShowData.value = fgm
    }

    /**
     * 设置对话框背景透明度
     * 0-1
     */
    protected open fun getDialogDimAmount(): Float {
        return 0.6f
    }

    /**
     * 触摸外面是否可以取消
     */
    protected open fun isCanceledOnTouchOutside() = false

    /**
     * 设置布局参数
     */
    protected open fun onRootViewLayoutParams(lp: FrameLayout.LayoutParams) {
        lp.gravity = Gravity.CENTER
    }

    /**
     * 设置对话框进入退出动画
     */
    @StyleRes
    protected open fun getDialogAnim(): Int? {
        return null
    }

    /**
     * 是否需要默认,进入退出动画
     */
    protected open fun isNeedDefaultAnim(): Boolean = true

}
